Fix generic SFC findComponent types - #2934
Conversation
✅ Deploy Preview for vue-test-utils-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
09567a6 to
93f1339
Compare
commit: |
| ): VueWrapper<InstanceType<T>> | ||
| // Generic SFCs emitted by vue-tsc have a generic call signature instead of | ||
| // the construct signature used by DefinedComponent. | ||
| findComponent<T extends <U>(...args: any[]) => VNode>(selector: T): VueWrapper |
There was a problem hiding this comment.
shouldn't the same be done for getComponent and findAllComponent?
There was a problem hiding this comment.
I'm also afraid that this matches any generic function returning VNode, including ordinary generic functional components. Those produce a DOMWrapperat runtime, so properties such as vm incorrectly type-check. The overload needs to identify vue-tsc’s generic-SFC shape
Address cexbrayat's review of PR vuejs#2934: 1. Tighten the generic SFC overload so it no longer matches ordinary generic functional components. The overload's return type uses a conditional on '"__ctx" extends keyof ReturnType<T>' to resolve to VueWrapper only when vue-tsc's __ctx discriminator is present in the selector's return type, with an 'unknown extends ReturnType<T>' guard ahead of it because Vue's FunctionalComponent call signature returns `any`, which would otherwise satisfy the discriminator and wrongly resolve to VueWrapper. Plain generic functional components and FunctionalComponent selectors fall through to DOMWrapper, so .vm no longer type-checks on them. 2. Apply the same discriminated overload to getComponent and findAllComponents so all three APIs handle vue-tsc generic SFCs consistently. 3. Extend test-dts/genericComponent.d-test.ts to cover all three APIs for vue-tsc-shaped generic SFCs (assert VueWrapper), plain generic functional components and FunctionalComponent-typed components (assert DOMWrapper + @ts-expect-error on .vm), plus WrapperLike-level assertions mirroring the BaseWrapper overloads. Signed-off-by: simonyang08 <ppt5928@gmail.com>
|
Thanks for the careful review — both points are addressed in the latest push (fea3b56). 1. Same treatment for Done — both now carry the same discriminated overload, with return types mirroring their existing overloads ( 2. Discriminating vue-tsc generic SFCs from ordinary generic functional components. Valid concern — the original constraint matched any While implementing, one more edge turned up that needed an explicit guard: Vue's
|
cexbrayat
left a comment
There was a problem hiding this comment.
Even if it is a bit too much of LLM gibberish, it sounds like a correct approach.
Just update the test and I think we'll be good to merge.
| __VLS_ctx?: any, | ||
| __VLS_expose?: any, | ||
| __VLS_setup?: Promise<any> | ||
| ) => VNode & { __ctx?: any } |
There was a problem hiding this comment.
I think it would be better to use a real <script setup generic="Item"> component in a .vue file imported by the test, instead of relying on internals of vue-tsc
Address cexbrayat's review of PR vuejs#2934: Replace the hand-written VueTscGenericSfc declaration in test-dts/genericComponent.d-test.ts with a real <script setup> generic SFC (test-dts/GenericSfc.vue) so the assertions exercise the actual shape vue-tsc emits, not a synthetic mock of its internals. Switch the tsd script in package.json from plain tsc to vue-tsc so the .vue import is resolved; vue-tsc was already a devDependency and was the tool that produced the __ctx-on-return-type shape the overload in src/baseWrapper.ts keys on. The three sets of assertions (vue-tsc SFC -> VueWrapper + .vm, plain generic functional component -> DOMWrapper + @ts-expect-error on .vm, FunctionalComponent shape -> DOMWrapper + @ts-expect-error on .vm, WrapperLike mirror) are preserved unchanged. Verified: - vue-tsc --noEmit -p test-dts/tsconfig.tsd.json: clean with src fix - same command against dist rebuilt from pre-fix src: fails as expected (generic functional component wrongly resolves as VueWrapper; existing @ts-expect-error directives report 'unused') - vitest run: 503 passed / 1 todo across 54 files (no runtime change) - oxlint / oxfmt --check on changed files: clean Signed-off-by: simonyang08 <ppt5928@gmail.com>
|
Thanks — fair point. Dropped the hand-written declaration and added The negative cases are unchanged: plain generic functionals still resolve to New commit: 7bd2bef. vue-tsc, vitest (56 focused / 503 full) and lint are all green. |
Fixes #2436
Summary
findComponentVueWrapperinstead of falling through toDOMWrapper<Node><script setup generic>componentsRoot cause
Generic SFCs emitted by Vue's
<script setup generic>syntax expose a generic call signature rather than the construct signature used byDefinedComponent. The existing overloads therefore selected the DOM-wrapper fallback.Compatibility
The new overload is limited to generic call signatures returning
VNode. Existing functional-component and defined-component overloads remain unchanged. The result intentionally uses an unparameterizedVueWrapperbecausefindComponentcannot instantiate the SFC's generic type parameter soundly.Validation
vue-tscreproduction - failed before, passed afterpnpm tsd- passedpnpm test --run tests/findComponent.spec.ts- 36 passedpnpm build- passedpnpm lint- passed with unrelated existing warningsgit diff --check- passedAI disclosure
This change was prepared with OpenAI Codex assistance and reviewed and validated locally by the contributor.